﻿using Ndns.ServerHost.Abstractions.Services;
using System;
using System.Threading;

namespace Ndns.ConsoleLogger
{
    class ConsoleLogger : ILogger
    {
        private const ConsoleColor LOG_TRACE_COLOR = ConsoleColor.DarkGray;
        private const ConsoleColor LOG_DEBUG_COLOR = ConsoleColor.DarkBlue;
        private const ConsoleColor LOG_INFO_COLOR = ConsoleColor.White;
        private const ConsoleColor LOG_WARNING_COLOR = ConsoleColor.Yellow;
        private const ConsoleColor LOG_ERROR_COLOR = ConsoleColor.Red;
        private const ConsoleColor LOG_FATAL_COLOR = ConsoleColor.Red;

        private const ConsoleColor LOG_EXCEPTION_COLOR = ConsoleColor.DarkRed;

        private readonly string _componentName;
        private readonly LogLevel _minimumLogLevel;
        private static SpinLock s_lock = new SpinLock();

        public ConsoleLogger(string componentName)
        {
            _componentName = componentName;
            _minimumLogLevel = LogLevel.None;
        }
        public ConsoleLogger(string componentName, LogLevel minimumLogLevel)
        {
            _componentName = componentName;
            _minimumLogLevel = minimumLogLevel;
        }

        private static ConsoleColor ChooseColor(LogLevel level)
        {
            switch (level)
            {
                case LogLevel.None:
                    return LOG_TRACE_COLOR;
                case LogLevel.Trace:
                    return LOG_TRACE_COLOR;
                case LogLevel.Debug:
                    return LOG_DEBUG_COLOR;
                case LogLevel.Info:
                    return LOG_INFO_COLOR;
                case LogLevel.Warning:
                    return LOG_WARNING_COLOR;
                case LogLevel.Error:
                    return LOG_ERROR_COLOR;
                case LogLevel.Fatal:
                    return LOG_FATAL_COLOR;
                default:
                    return LOG_TRACE_COLOR;
            }
        }

        public void Log(string traceIdentifier, LogLevel level, string message, Exception exception)
        {
            if (level < _minimumLogLevel)
            {
                return;
            }

            ConsoleColor levelColor = ChooseColor(level);

            if (string.IsNullOrEmpty(traceIdentifier))
            {
                traceIdentifier = "UNDEFINED";
            }
            ConsoleColor originalColor;
            bool lockTaken = false;
            try
            {
                s_lock.Enter(ref lockTaken);

                originalColor = Console.ForegroundColor;
                Console.ForegroundColor = levelColor;
                Console.Write($"{traceIdentifier,-14} {string.Concat("<", level, ">"),-8}");
                Console.WriteLine(message);
                Console.ForegroundColor = originalColor;
                if (exception != null)
                {
                    originalColor = Console.ForegroundColor;
                    Console.ForegroundColor = LOG_EXCEPTION_COLOR;
                    Console.WriteLine(exception.ToString());
                    Console.ForegroundColor = originalColor;
                }
            }
            finally
            {
                if (lockTaken)
                {
                    s_lock.Exit();
                }
            }
        }
    }
}
